package sub

import (
	"bufio"
	"fmt"
	psnet "github.com/shirou/gopsutil/v3/net"
	"github.com/urfave/cli/v2"
	"github.com/yusufpapurcu/wmi"
	"lib/structs/ams"
	"lib/utils"
	"net"
	"os"
	"strings"
)

var IdpPlugin = new(idpPlugin)

type idpPlugin struct {
}

func (s idpPlugin) IdpCommand() *cli.Command {
	var comm = &cli.Command{
		Name:      ams.IDP,
		Usage:     "idp 信息",
		UsageText: fmt.Sprintf("eg: %s %s", ams.IDP, "-code=1"),
		Flags: []cli.Flag{
			&cli.IntFlag{
				Name:  "code",
				Usage: "获取指定idp信息",
			},
		},
	}
	comm.Action = func(ctx *cli.Context) error {
		var (
			data any
			err  error
		)
		switch ctx.Int("code") {
		case 1: // cpu
			data, err = s.GetCpuInfo()
		case 2: // 内存
			data, err = s.GetMemory()
		case 3: // 硬盘
			data, err = s.GetDisk()
		case 4: // 逻辑磁盘
			data, err = s.GetLogicDisk()
		case 5: // 主板
			data, err = s.GetMainBoard()
		case 6: // 系统概述
			data, err = s.GetSystemInfo()
		case 7: // 开机启动项
			data, err = s.GetBootCommand()
		case 8: // 活跃网卡信息
			data, err = s.GetActiveNetInfo()
		case 9: // 服务信息
			data, err = s.GetService()
		default:
			err = fmt.Errorf("未知参数")
		}
		if err != nil {
			return cli.Exit(fmt.Sprintf("获取idp信息时发生错误:[%v]", err), 1)
		}
		w := bufio.NewWriter(os.Stdout)
		_, _ = w.WriteString(utils.Obj2Str(data))
		_ = w.Flush()
		return nil
	}
	return comm
}

// GetCpuInfo 获取cpu信息
func (s idpPlugin) GetCpuInfo() (li []ams.IdpForCpu, err error) {
	err = wmi.Query("SELECT * FROM Win32_Processor", &li)
	return
}

// GetMemory 获取内存信息
func (s idpPlugin) GetMemory() (li []ams.IdpForMemory, err error) {
	err = wmi.Query("SELECT * FROM Win32_PhysicalMemory", &li)
	return
}

// GetDisk 获取磁盘信息
func (s idpPlugin) GetDisk() (li []ams.IdpForDisk, err error) {
	var data = make([]ams.IdpForDisk, 0)
	err = wmi.Query("SELECT * FROM Win32_DiskDrive", &data)
	if err != nil {
		return
	}
	li = make([]ams.IdpForDisk, 0)
	for index := range data {
		data[index].SerialNumber = strings.TrimSpace(data[index].SerialNumber)
		if data[index].Size != 0 {
			li = append(li, data[index])
		}
	}
	return
}

// GetLogicDisk 获取逻辑磁盘信息
func (s idpPlugin) GetLogicDisk() (li []ams.IdpForLogicDisk, err error) {
	var data = make([]ams.IdpForLogicDisk, 0)
	err = wmi.Query("SELECT * FROM Win32_LogicalDisk", &data)
	if err != nil {
		return
	}
	li = make([]ams.IdpForLogicDisk, 0)
	for index := range data {
		if data[index].VolumeSerialNumber != "" {
			rd := ams.IdpForLogicDisk{
				Caption:            data[index].Caption,
				Description:        data[index].Description,
				DeviceID:           data[index].DeviceID,
				DriveType:          data[index].DriveType,
				FileSystem:         data[index].FileSystem,
				FreeSpace:          data[index].FreeSpace,
				Size:               data[index].Size,
				SupportsDiskQuotas: data[index].SupportsDiskQuotas,
				VolumeName:         data[index].VolumeName,
				VolumeSerialNumber: data[index].VolumeSerialNumber,
			}
			li = append(li, rd)
		}
	}
	return
}

// GetMainBoard 获取主板信息
func (s idpPlugin) GetMainBoard() (li []ams.IdpForMainBoard, err error) {
	err = wmi.Query("SELECT * FROM Win32_BaseBoard", &li)
	return
}

// GetSystemInfo 获取系统概述信息
func (s idpPlugin) GetSystemInfo() (li []ams.IdpForSystem, err error) {
	err = wmi.Query("select * from Win32_ComputerSystem", &li)
	return
}

// GetBootCommand 获取开机启动项信息
func (s idpPlugin) GetBootCommand() (li []ams.IdpForBootCommand, err error) {
	err = wmi.Query("select * from Win32_StartupCommand", &li)
	return
}

// GetActiveNetInfo 获取活跃网络信息
func (s idpPlugin) GetActiveNetInfo() (out ams.IdpForActiveMac, err error) {
	var (
		ip  string
		mac string
	)
	ip, err = s.getOutBoundIP()
	if err != nil {
		return
	}
	mac, err = s.GetActiveMac(ip)
	if err != nil {
		return
	}
	var data []ams.IdpForNetWork
	err = wmi.Query("SELECT * FROM Win32_NetworkAdapter WHERE (NetConnectionStatus = 2) AND (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))", &data)
	if err != nil {
		return
	}
	for _, item := range data {
		if strings.ReplaceAll(strings.ToLower(item.MACAddress), ":", "-") == mac {
			out = ams.IdpForActiveMac{
				Ip:              ip,
				Mac:             mac,
				Index:           item.Index,
				Name:            item.Name,
				Caption:         item.Caption,
				Manufacturer:    item.Manufacturer,
				NetConnectionID: item.NetConnectionID,
			}
			return
		}
	}
	err = fmt.Errorf("未获取到规则内的活跃网卡信息")
	return
}

func (s idpPlugin) getOutBoundIP() (ip string, err error) {
	var (
		conn net.Conn
	)
	conn, err = net.Dial("udp", "8.8.8.8:80")
	if err != nil {
		return "", err
	}
	localAdd := conn.LocalAddr()
	ip = strings.Split(localAdd.String(), ":")[0]
	return ip, nil
}

func (s idpPlugin) GetActiveMac(ip string) (mac string, err error) {
	var (
		psn psnet.InterfaceStatList
	)
	if psn, err = psnet.Interfaces(); err != nil {
		return
	}
	for _, item := range psn {
		if len(item.Addrs) == 2 {
			ipv4 := item.Addrs[1].Addr
			ipv4 = ipv4[:strings.LastIndex(ipv4, "/")]
			if ipv4 == ip {
				mac = item.HardwareAddr
				mac = strings.ReplaceAll(mac, ":", "-")
				return
			}
		}
	}
	err = fmt.Errorf("ip not found")
	return
}

// GetService 获取服务信息
func (s idpPlugin) GetService() (li []ams.IdpForService, err error) {
	err = wmi.Query("select * from Win32_Service", &li)
	return
}
